function isObject(e) {
	return e && typeof e === 'object'
}

let activeEffect = null
let targetMap = new Map()
function track(target, key) {
	// 这部分做的事情就是把key值对应的watchers收集起来，vue2中由于使用的是Object.defineProperty，按照明确的key值
	// 去确定的，由于key值提前知道，因此每个key对应的dep可以在遍历key的时候存到闭包里
	// proxy提前是拿不到key值的，在get函数中才能拿到，所以没办法存到闭包中，就只要存到全局里了
	let targetList = targetMap.get(target)
	if (!targetMap) {
		targetList = new Map()
		targetMap.set(target, targetList)
	}
	let keyList = targetList.get(key)
	if (!keyList) {
		keyList = new Set()
		targetList.set(key, keyList)
	}
	if (!keyList.has(activeEffect)) keyList.add(activeEffect)
}
function trigger(target, key) {
	const depsMap = targetMap.get(target)
	if (depsMap) {
		(depsMap.get(key) || []).forEach(effect => effect.run())
	}
}
function reactive(target) {
	if (!isObject(target)) return
	return new Proxy(target, key, {
		get(target, key, receiver) {
			const ret = Reflect.get(target, key, receiver)
			track(target, key)
			return isObject(ret) ? reactive(ret) : ret
		},
		set(target, key, value, receiver) {
			Reflect.set(target, key, value, receiver)
			trigger(target, key)
			return true
		}
	})
}

function effect(fn,options){
	let __effect = new ReactiveEffect(fn)
	options.lazy || __effect.run()
	return __effect
}

class ReactiveEffect {
	constructor(fn){
		this.fn = fn
	}
	run(){
		activeEffect = this
		return this.fn()
	}
}

function computed(fn){
	/* 
		此处由于是简写，所以看起来和vue2源码中的computed差别有点大，但是本质的原理都是类似的。effect的作用和vue2中的
		watcher类似，都是存储一个回调（或者说setter函数），然后自身能被属性的getter收集，当属性变化的时候，能够通知
		到自己去执行回调函数。
	 */
	let __computed
	const e = effect
	__computed = {
		get value(){
			return e.fn()
		}
	}

	return __computed
}

function ref(){
	class RefImpl {
		constructor(init){
			this.__value = init
		}
		// 这个ref的实现原理非常简单，实例化出一个对象，然后借用track方法，说白了就是把实例当target，固定的value字段当
		// key，把实例对象整成代理形式
		get value(){
			track(this,'value')
			return this.__value
		}

		set value(newVal){
			this.__value = newVal
			trigger(this,'value')
		}
	}
	return new RefImpl(init)
}
